package cn.lg.soar.system.biz.modules.auth.service.impl;

import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.database.base.service.impl.BaseServiceImpl;
import cn.lg.soar.system.biz.config.SystemCacheKey;
import cn.lg.soar.system.biz.modules.auth.entity.DataRuleItem;
import cn.lg.soar.system.biz.modules.auth.entity.DataScope;
import cn.lg.soar.system.biz.modules.auth.mapper.DataScopeMapper;
import cn.lg.soar.system.biz.modules.auth.model.DataRuleItemDTO;
import cn.lg.soar.system.biz.modules.auth.model.RoleDataScopeVO;
import cn.lg.soar.system.biz.modules.auth.service.IDataRuleItemService;
import cn.lg.soar.system.biz.modules.auth.service.IDataScopeService;
import cn.lg.soar.system.biz.modules.auth.service.IResourceService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * DataScope服务层实现
 * 数据源
 * @author luguoxiang
 * @since 2022-04-30
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Primary
public class DataScopeServiceImpl extends BaseServiceImpl<DataScopeMapper, DataScope> implements IDataScopeService {

    private IDataRuleItemService dataRuleItemService;
    private IResourceService resourceService;

    public DataScopeServiceImpl(IDataRuleItemService dataRuleItemService, IResourceService resourceService) {
        this.dataRuleItemService = dataRuleItemService;
        this.resourceService = resourceService;
    }

    @Override
    public boolean save(DataScope entity) {
        boolean flag = super.save(entity);
        // 清理缓存
        resourceService.removeCacheByResourceId(Collections.singletonList(entity.getResourceId()));
        return flag;
    }

    @Override
    public boolean updateById(DataScope entity) {
        boolean flag = super.updateById(entity);
        // 清理缓存
        resourceService.removeCacheByResourceId(Collections.singletonList(entity.getResourceId()));
        return flag;
    }

    @Override
    public boolean removeByIds(Collection<?> list) {
        List<DataScope> dataScopes = list(
                Wrappers.<DataScope>lambdaQuery()
                        .select(DataScope::getResourceId)
                        .in(DataScope::getId, list)
        );
        boolean b = super.removeByIds(list);
        // 清理缓存
        resourceService.removeCacheByResourceId(dataScopes.stream().map(DataScope::getResourceId).collect(Collectors.toSet()));
        return b;
    }

    @Cacheable(value = SystemCacheKey.RESOURCE_TO_RULEMAP, key = "#p0")
    @Override
    public Map<Long, List<DataRuleItemDTO>> getResourceRuleMap(String resourceCode) {
        // 查规则id
        List<DataScope> list = baseMapper.listByResourceCode(resourceCode);
        if (DataUtil.isEmpty(list)) {
            return Collections.emptyMap();
        }
        // 组装数据
        Map<Long, Long> idMap = new HashMap<>(list.size() + 1);
        for (DataScope dataScope : list) {
            idMap.put(dataScope.getRoleId(), dataScope.getRuleId());
        }
        // 查规则明细
        List<DataRuleItem> items = dataRuleItemService.list(
                Wrappers.<DataRuleItem>lambdaQuery().in(DataRuleItem::getRuleId, idMap.values())
        );
        // 组装成角色和规则明细的映射
        Map<Long, List<DataRuleItem>> itemMap = items.stream().collect(Collectors.groupingBy(DataRuleItem::getRuleId));
        Map<Long, List<DataRuleItemDTO>> res = new HashMap<>(idMap.size());
        idMap.forEach((roleId, ruleId) -> {
            List<DataRuleItem> is = itemMap.computeIfAbsent(ruleId, x -> Collections.emptyList());
            List<DataRuleItemDTO> collect = is.stream().map(x -> {
                DataRuleItemDTO filter = new DataRuleItemDTO();
                filter.setColumnName(x.getColumnName());
                filter.setExpression(x.getExpression());
                filter.setProvideType(x.getProvideType());
                filter.setColumnValue(x.getColumnValue());
                filter.setSpliceType(x.getSpliceType());
                return filter;
            }).collect(Collectors.toList());
            res.put(roleId,  collect);
        });
        return res;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setRuleDataScope(RoleDataScopeVO vo) {
        List<Long> roleIds = vo.getRoleIds();
        List<DataScope> dataScopes = vo.getDataScopes();
        List<DataScope> list = new ArrayList<>(roleIds.size() * dataScopes.size());
        for (Long roleId : roleIds) {
            for (DataScope x : dataScopes) {
                DataScope entity = new DataScope();
                entity.setRoleId(roleId);
                entity.setResourceId(x.getResourceId());
                entity.setRuleId(x.getRuleId());
                list.add(entity);
            }
        }
        // 旧的
        List<DataScope> olds = list(
                Wrappers.<DataScope>lambdaQuery()
                        .select(DataScope::getResourceId)
                        .in(DataScope::getRoleId, roleIds)
        );
        remove(
                Wrappers.<DataScope>lambdaQuery()
                        .in(DataScope::getRoleId, roleIds)
        );
        if (!list.isEmpty()) {
            AssertUtil.isTrue(saveBatch(list), "操作失败");
        }
        if (!dataScopes.isEmpty()) {
            resourceService.removeCacheByResourceId(dataScopes.stream().map(DataScope::getResourceId).collect(Collectors.toSet()));
        }
        if (!olds.isEmpty()) {
            resourceService.removeCacheByResourceId(olds.stream().map(DataScope::getResourceId).collect(Collectors.toSet()));
        }
    }

    @Override
    public List<DataScope> getRuleDataScope(Long roleId) {
        return list(
                Wrappers.<DataScope>lambdaQuery()
                        .select(DataScope::getResourceId, DataScope::getRuleId)
                        .eq(DataScope::getRoleId, roleId)
        );
    }

}
